/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package nonequidistant.FEMSolver1D;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import jmeshless.NewOkCancelDialog;
import nonequidistant.FEMShapeFunctions1D.FEMShapeFunction1D1Pow;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import syntaxanalyser.PostfiksX;
import HashMatrix2.HashMatrix2;
import HashMatrix2.LUFactorization;
import Integration.IFunction1D;

/**
 *
 * @author mark_o
 */
public class AdaptiveScheme {
    HashMatrix2 A;
    double[] b;
    ArrayList<Double> NodeList;
    ArrayList<FEMShapeFunction1D1Pow> FuncList;

    String pString="1";
    String wString="0";
    String qString="10";
    String fString="100";

    IFunction1D p;
    IFunction1D w;
    IFunction1D q;
    IFunction1D f;

    double left;
    double right;

    boolean DirihetA;
    double AVal;
    boolean DirihetB;
    double BVal;

    public AdaptiveScheme(ArrayList<Double> NodeList) {
        this.NodeList = NodeList;
        A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, NodeList.size());
        b = new double[NodeList.size()];
        generateFunctions();

    }

    private void generateFunctions(){
        FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
        FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(0), 0.01,NodeList.get(1) - NodeList.get(0)));
        for (int i = 1; i < NodeList.size()-1; i++) {
            double h1 = NodeList.get(i) - NodeList.get(i-1);
            double h2 = NodeList.get(i+1) - NodeList.get(i);
            FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(i), h1,h2));
        }
        int n = NodeList.size()-1;
        FuncList.add(new FEMShapeFunction1D1Pow(NodeList.get(n), NodeList.get(n) - NodeList.get(n-1), 0.01));
    }

    private void generateCoefFuncs() {
//        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));
//
//        gen.setLeft(left);
//        gen.setRight(right);

        p = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(pString, x);
                } catch (Exception ex) {
                    Logger.getLogger(AdaptiveScheme.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        w = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(wString, x);
                } catch (Exception ex) {
                    Logger.getLogger(AdaptiveScheme.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        q = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(qString, x);
                } catch (Exception ex) {
                    Logger.getLogger(AdaptiveScheme.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        f = new IFunction1D() {

            public double calculate(double x) {
                try {
                    return PostfiksX.Calculate(fString, x);
                } catch (Exception ex) {
                    Logger.getLogger(AdaptiveScheme.class.getName()).log(Level.SEVERE, null, ex);
                }
                return 0;
            }

            public double calculateDerivaty(double x) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };


    }

    private void generateMatrix(){
        A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, NodeList.size());
        b = new double[NodeList.size()];
//        MatrixGenerator1 gen = new MatrixGenerator1(NodeList.get(0),NodeList.get(NodeList.size()-1));
        StatMatrixGenerator gen = new StatMatrixGenerator();
        gen.setLeft(left);
        gen.setRight(right);

            gen.setF1(FuncList.get(0));
            gen.setF2(FuncList.get(1));
            double[][] tmp = null;
            double[] tmpb = null;

        for (int i = 0; i < b.length-1; i++) {
            gen.setF1(FuncList.get(i));
            gen.setF2(FuncList.get(i+1));
            tmp = gen.getAll(p, q, w);
            tmpb = gen.getFe(f);

            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
            b[i]+=tmpb[0];
            b[i+1]+=tmpb[1];
        }

//        gen.setLeft(left);
//        gen.setRight(right);
//
//        for (int i = 0; i < b.length; i++) {
//            //IFunction1D f1 = FuncList.get(i);
//            gen.setF1(FuncList.get(i));
//            gen.setF2(FuncList.get(i));
//            //A.setValue(i, i, gen.getKe(p)+gen.getAdv(w)+gen.getMe(q));
//            for (int j = 0; j < b.length; j++) {
//                gen.setF2(FuncList.get(j));
//                double val = gen.getKe(p)+gen.getAdv(w)+gen.getMe(q);
//                A.setValue(i, j, val);
//            }
//            b[i] = gen.getFe(f);
//        }

//        System.out.println("\t==========================================");
//        for (int i = 0; i < b.length; i++) {
//            for (int j = 0; j < b.length; j++) {
//                System.out.print(A.getValue(i, j)+"\t");
//            }
//            System.out.println("\t"+b[i]);
//        }
//        System.out.println("\t==========================================");
    }

    private double[] Solve(){
        //
//        Gauss lu = new Gauss(A);

        //Neyman a:
        //b[0]+=1;

        //Dirihlet a:
        if (DirihetA) {
            b[0] = AVal;
            b[1]-= AVal*A.getValue(1, 0);
            A.setValue(0, 0, 1);
            A.setValue(0, 1, 0);
            A.setValue(1, 0, 0);
        }else{
            b[0]+=AVal;
        }


        //Dirihlet b:
        if (DirihetB) {
            b[b.length-1] = BVal;
            b[b.length-2]-= BVal*A.getValue(b.length-2, b.length-1);
            A.setValue(A.getN()-1, A.getN()-1, 1);
            A.setValue(A.getN()-1, A.getN()-2, 0);
            A.setValue(A.getN()-2, A.getN()-1, 0);
        }else{
            b[b.length-1]+=BVal;
        }
        LUFactorization lu = new LUFactorization(A);
        double[] res = lu.calculate(b);
//        for (int j = 0; j < b.length; j++) {
//            System.out.println(NodeList.get(j)+"\t"+res[j]);
//        }
        return res;
    }

    public HashMatrix2 getA() {
        return A;
    }

    public double[] getB() {
        return b;
    }

    public void setAVal(double AVal) {
        this.AVal = AVal;
    }

    public void setBVal(double BVal) {
        this.BVal = BVal;
    }

    public void setDirihetA(boolean DirihetA) {
        this.DirihetA = DirihetA;
    }

    public void setDirihetB(boolean DirihetB) {
        this.DirihetB = DirihetB;
    }

    public void setfString(String fString) {
        this.fString = fString;
    }

    public void setpString(String pString) {
        this.pString = pString;
    }

    public void setqString(String qString) {
        this.qString = qString;
    }

    public void setwString(String wString) {
        this.wString = wString;
    }

    public void setLeft(double left) {
        this.left = left;
    }

    public void setRight(double right) {
        this.right = right;
    }

    private ArrayList<Double> generateMidPoints(){
        ArrayList<Double> list = new ArrayList<Double>();
        for (int i = 0; i < NodeList.size()-1; i++) {
            list.add( (NodeList.get(i) + NodeList.get(i+1)) / 2.0);
        }
        return list;
    }


    public double[] adaptate(double O){
        double[] res = null;
        this.generateCoefFuncs();
        int num = 0;
        while(true){
            this.generateFunctions();
            this.generateMatrix();
            res = this.Solve();
            
            
            XYSeriesCollection col  = new XYSeriesCollection();
            XYSeries series1 = new XYSeries("func", true, true);
            for (int i = 0; i < res.length; i++) {
            	series1.add((double)NodeList.get(i),res[i]);
    		}
            col.addSeries(series1);
            
            

            
            
            FEMResult femres = new FEMResult(res, FuncList);
            XYSeries series2 = new XYSeries("func", true, true);
//            XYSeries series3 = new XYSeries("func", true, true);
//            for (int i = 0; i < res.length; i++) {
////            	series2.add((double)NodeList.get(i),femres.calculate(NodeList.get(i)));
////            	series3.add((double)NodeList.get(i),femres.calculateDerivaty(NodeList.get(i)));
//            	double x = NodeList.get(i);
////            	double tmp = (1.0 / (Math.exp(100) - 1) * (1- Math.exp(100*x)) + x);
//            	double tmp = -(50*x*x-50*x);
//	            series2.add(x,tmp);
//    		}
            
//            double a = 0.0;
//            double b = 1.0;
//            int N = 40;
//            double h = (b-a)/N;
//            this.NodeList = new ArrayList<Double>();
//            for (int i = 0; i <= N; i++) {
//            	this.NodeList.add(a+h*i);
//            }
//            
//            this.generateFunctions();
//            this.generateMatrix();
//            res = this.Solve();
//            XYSeries series3 = new XYSeries("func", true, true);
//            for (int i = 0; i < res.length; i++) {
//            	series3.add((double)NodeList.get(i),res[i]);
//    		}
//            col.addSeries(series3);
            
            
            double x = 0.0;
	        while(x<=1.0001){
	        	double tmp = (1.0 / (Math.exp(100) - 1) * (1- Math.exp(100*x)) + x);///-(50*x*x-50*x);
	            series2.add(x,tmp);
	            x+=0.001;
	        }
            col.addSeries(series2);
//            col.addSeries(series3);
            NewOkCancelDialog dialog = new NewOkCancelDialog(null, false, col);
            dialog.setLocationRelativeTo(null);
            dialog.setVisible(true);
            
            boolean key = false;
            
            series1 = new XYSeries("Похибка", true, true);
//            FEMResult err = error2(A,femres);
            FEMResult err = error(femres);
            x = 0.0;
//	        while(x<=1.0001){
//	            series1.add(x,err.calculate(x));
//	            x+=0.002;
//	        }
            for (int i = 0; i < err.res.length; i++) {
            	series1.add(err.FuncList.get(i).getXi(),err.res[i]);
			}
//
	        dialog = new NewOkCancelDialog(null, false, new XYSeriesCollection(series1));
	        dialog.setLocationRelativeTo(null);
	        dialog.setVisible(true);
            
//            FEMResult err = error(femres);
//            
////            ArrayList<Double> list = new ArrayList<Double>();
//            for (int i = 0; i < FuncList.size()-1; i++) {
//                double mid = ( (FuncList.get(i).getXi() + FuncList.get(i+1).getXi()) / 2.0);
//                double locErr = err.calculate(mid);
//                if (Math.abs(locErr)>O) {
//					int num = (int) (Math.abs(locErr)/O);
//					if(num==1){num++;}
//					double locH =  (FuncList.get(i+1).getXi() - FuncList.get(i).getXi()) / num ;
//					for (int j = 1; j < num; j++) {
//						NodeList.add(FuncList.get(i).getXi() + j*locH);
//					}
//					key = true;
//				}
//            }
            
            
            
            
            
            
//            adaptate2(res.length-2, res.length-1, res[res.length-2], res[res.length-1]);
//            adaptate2(res.length-3, res.length-2, res[res.length-3], res[res.length-2]);
            
            // near boundaries  
//            double[] errr = errorBoundaries(true, res[0], res[1]);
//            double  error = 0.0;
//        	for (int j = 0; j < errr.length; j++) {
//				error+=errr[j];
//			}
//        	
//        	error/=errr.length;
//        	
//        	if (Math.abs(error)>O) {
//                key = true;
//                NodeList.add((NodeList.get(0)+NodeList.get(1)) / 2.0);
//                System.out.println((NodeList.get(0)+NodeList.get(1)) / 2.0);
//            }
//        	
//        	errr = errorBoundaries(false, res[res.length-2], res[res.length-1]);
//            error = 0.0;
//        	for (int j = 0; j < errr.length; j++) {
//				error+=errr[j];
//			}
//        	
//        	error/=errr.length;
//        	
//        	if (Math.abs(error)>O) {
//                key = true;
//                NodeList.add((NodeList.get(res.length-1)+NodeList.get(res.length-2)) / 2.0);
//                System.out.println((NodeList.get(res.length-1)+NodeList.get(res.length-2)) / 2.0);
//            }
//        	
//            //inside
//            for (int i = 1; i < res.length-2; i++) {
//            	errr = errorInside(i, i+1, res[i], res[i+1]);
//            	
//            	error = 0.0;
//            	for (int j = 0; j < errr.length; j++) {
//					error+=errr[j];
//				}
//            	
//            	error/=errr.length;
//            	
//            	if ((Math.abs(error)>O)||(Double.isNaN(error))) {
//                    key = true;
//                    NodeList.add((NodeList.get(i)+NodeList.get(i+1)) / 2.0);
//                    System.out.println((NodeList.get(i)+NodeList.get(i+1)) / 2.0);
//                    if (Double.isNaN(error)) {
//						System.out.println("nan"+res.length);
//					}
//                }
//			}
            key = true;
            num++;
            if (num==5) {
				break;
			}
            for (int i = 0; i < res.length-1; i++) {
            	if (err.calculate((NodeList.get(i)+NodeList.get(i+1))/2.0)>O) {
            		NodeList.add((NodeList.get(i)+NodeList.get(i+1))/2.0);
				}
				
			}
            System.out.println("============================================================================");
            System.out.println("n = "+res.length);
            if (key) {
                Double[] tmp = new Double[NodeList.size()];
                NodeList.toArray(tmp);
                Arrays.sort(tmp);
                
                NodeList = new ArrayList<Double>();
                NodeList.addAll(Arrays.asList(tmp));
                for (int i = 0; i < NodeList.size(); i++) {
                	System.out.println("NodeList.add(new Particle(" +
                			NodeList.get(i) +
                			", rho," +
                			i +
                			"));\n NodeList.get(NodeList.size()-1).setRho(rho);");
				}
            }else{
                break;
            }
            
            

//            for (int j = 0; j < b.length; j++) {
//                System.out.println(NodeList.get(j)+"\t"+res[j]);
//            }
            

//            // перевірка умови нормал сітки...
//            FEMResult femres = new FEMResult(res, FuncList);
//
//            //1. обчислюєм похідну по середині відрізків-елементів.
//                ArrayList<Double> MidPoints = this.generateMidPoints();
//                ArrayList<Double> derivaties = new ArrayList<Double>();
//
//                for (int i = 0; i < MidPoints.size(); i++) {
//                    derivaties.add(femres.calculateDerivaty(MidPoints.get(i)));
//                }
//            //обчислюємо норму
//                ArrayList<Double> D = new ArrayList<Double>();
//                D.add(Math.abs(femres.calculate(MidPoints.get(0)) - femres.calculate(MidPoints.get(1))) / Math.abs( MidPoints.get(0) - MidPoints.get(1) ));
//                for (int i = 1; i < MidPoints.size()-1; i++) {
//                    double d1 = Math.abs(femres.calculate(MidPoints.get(i)) - femres.calculate(MidPoints.get(i-1))) / Math.abs( MidPoints.get(i) - MidPoints.get(i-1) );
//                    double d2 = Math.abs(femres.calculate(MidPoints.get(i)) - femres.calculate(MidPoints.get(i+1))) / Math.abs( MidPoints.get(i) - MidPoints.get(i+1) );
//                    D.add(Math.max(d1, d2));
//                }
//                D.add(Math.abs(femres.calculate(MidPoints.get( MidPoints.size()-1 )) - femres.calculate(MidPoints.get(MidPoints.size()-2))) / Math.abs( MidPoints.get(MidPoints.size()-1 ) - MidPoints.get(MidPoints.size()-2) ));
//
//            //обчислюємо Dhk
////                double max = -1000000000000000.0;
////                int pos = 0;
//                for (int k = 0; k < D.size(); k++) {
//                    Double d1 = D.get(k);
//                    //double hk = this.FuncList.get(k).gethLeft()+this.FuncList.get(k).gethRight();
//                    double hk = this.FuncList.get(k).gethRight();
//                    hk=1.0;
//                    D.set(k, d1*hk);
////                    if (max<D.get(k)) {
////                        max = d1*hk;
////                        pos = k;
////                    }
////                    System.out.println("============================================================================");
////                    for (int j = 0; j < D.size(); j++) {
////                        System.out.println(NodeList.get(j)+"\t"+D.get(j));
////                    }
////                    System.out.println("============================================================================");
//                }
//            // додаємо нові елементи
//                boolean key = false;
//                
////                    if (D.get(pos)>O) {
////                        key = true;
////                        NodeList.add((NodeList.get(pos)+NodeList.get(pos+1)) / 2.0);
////                    }
//
//                for (int i = 0; i < D.size(); i++) {
//                    Double d1 = D.get(i);
//                    if (d1>O) {
//                        key = true;
//                        NodeList.add((NodeList.get(i)+NodeList.get(i+1)) / 2.0);
//                    }
//                }
//
//                if (key) {
//                    Double[] tmp = new Double[NodeList.size()];
//                    NodeList.toArray(tmp);
//                    Arrays.sort(tmp);
//                    
//                    NodeList = new ArrayList<Double>();
//                    NodeList.addAll(Arrays.asList(tmp));
//                }else{
//                    break;
//                }


            
        }
        	
            for (int j = 0; j < b.length; j++) {
            	System.out.println(NodeList.get(j)+"\t"+res[j]);
            }
        
//            for (int j = 0; j < b.length; j++) {
//                System.out.println("\t\tlist.add("+NodeList.get(j)+");");
//            }

//        for (int i = 0; i < b.length; i++) {
//            for (int j = 0; j < b.length; j++) {
//                System.out.print(A.getValue(i, j)+"\t");
//            }
//            System.out.println("\t"+b[i]);
//        }
        return res;

    }
    
    public FEMResult error(final FEMResult femres) {
//    	int n = 15;
//    	n = b.length*2;
    	ArrayList<FEMShapeFunction1D1Pow> FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
//		double h1 = (this.right-this.left)/(double)(n-1);
    	
    	double h1 = 0.01;
    	double h2 = this.FuncList.get(1).getXi() - this.FuncList.get(0).getXi();
    	h2/=2.0;
    	FuncList.add(new FEMShapeFunction1D1Pow(this.left, h1, h2));
    	FuncList.add(new FEMShapeFunction1D1Pow(this.left + h2, h2, h2));
    		
    		
        for (int i = 1; i < this.FuncList.size()-1; i++) {
        	h1 = this.FuncList.get(i).getXi() - this.FuncList.get(i-1).getXi();
        	h1/=2.0;
        	h2 = this.FuncList.get(i+1).getXi() - this.FuncList.get(i).getXi();
        	h2/=2.0;
        	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(i).getXi(), h1, h2));
        	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(i).getXi() + h2, h2, h2));
        }
        
        h1 = this.FuncList.get(this.FuncList.size()-1).getXi() - this.FuncList.get(this.FuncList.size()-2).getXi();
    	h1/=2.0;
    	h2=0.001;
    	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(this.FuncList.size()-1).getXi(), h1, h2));
        int n = FuncList.size();
		double res[] = null;
		HashMatrix2 A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, n);
		double[] b = new double[n];
		
        
        StatMatrixGenerator gen = new StatMatrixGenerator();
        gen.setLeft(left);
        gen.setRight(right);

            gen.setF1(FuncList.get(0));
            gen.setF2(FuncList.get(1));
            double[][] tmp = null;
            double[] tmpb = null;

        for (int i = 0; i < b.length-1; i++) {
            gen.setF1(FuncList.get(i));
            gen.setF2(FuncList.get(i+1));
            tmp = gen.getAll(p, q, w);
            tmpb = gen.getFe(f);

            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
            b[i]+=tmpb[0];
            b[i+1]+=tmpb[1];
        }
        
//        GaussQuadrature gau = new GaussQuadrature(10);
//        
//        
//        for (int i = 0; i < b.length; i++) {
//        	final FEMShapeFunction1D1Pow v = FuncList.get(i);
//        	IFunction1D fff = new IFunction1D() {
//				
//				@Override
//				public double calculateDerivaty(double x) {
//					// TODO Auto-generated method stub
//					return 0;
//				}
//				
//				@Override
//				public double calculate(double x) {
//					double uVal = femres.calculate(x);//f1.calculate(x)*u1+f2.calculate(x)*u2;
//					double uDerVal = femres.calculateDerivaty(x);//f1.calculateDerivaty(x)*u1+f2.calculateDerivaty(x)*u2;
//					return uDerVal*p.calculate(x)*v.calculateDerivaty(x) + uVal*w.calculate(x)*v.calculateDerivaty(x) + uVal*q.calculate(x)*v.calculate(x);
//				}
//			};
//			
//			double tmpxz = gau.justGauss(this.left, this.right, fff); 
////			System.out.println(tmpxz);
////			b[i] -= tmpxz;
//		}
        
        b[0] = 0.0;
        A.setValue(0, 1, 0.0);
        A.setValue(0, 0, 1.0);
		b[n-1] = 0.0;
		A.setValue(n-1, n-2, 0.0);
		A.setValue(n-1, n-1, 1.0);
        
        
//        double[] tmpU = new double[b.length];
		for (int j = 0; j < b.length; j++) {
			ArrayList<Integer> pos = A.getJRowIndex(j);
			double tmpxz = 0.0;
//			double tmpxz2 = 0.0;
			for (int i = 0; i < pos.size(); i++) {
				tmpxz += A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
//				tmpxz2 += this.A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
			}
			b[j]-=tmpxz;
		}
        
//		b[0]+= (f1.calculateDerivaty((f1.getXi()-f1.gethLeft()/2.0)) + f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0)))*(u1)/2.0  - f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0))*u1;
//		b[n-1]+= (f2.calculateDerivaty((f2.getXi()-f2.gethLeft()/2.0)) + f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0)))*(u2)/2.0 - f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0))*u2;
        

        LUFactorization lu = new LUFactorization(A);
        res = lu.calculate(b);
        for (int i = 0; i < res.length; i++) {
			res[i] = Math.abs(res[i]);
		}
        
//        for (int i = 0; i < res.length; i++) {
//			System.out.println(res[i]);
//		}
//        	XYSeriesCollection col = new XYSeriesCollection();
//        
//            		 	XYSeries series = new XYSeries("", true, true);
//            	        for (int i = 0; i < NodeList.size(); i++) {
//        					series.add((double)NodeList.get(i),res[i]);
//        				}
//            	        col.addSeries(series);
//        
//                NewOkCancelDialog dialog = new NewOkCancelDialog(null, false, col);
//                dialog.setLocationRelativeTo(null);
//                dialog.setVisible(true);
		
		return new FEMResult(res, FuncList);
	}
    
    public FEMResult error2(HashMatrix2 A, final FEMResult femres) {
    	ArrayList<FEMShapeFunction1D1Pow> FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
    	double h1 = 0.01;
    	double h2 = this.FuncList.get(1).getXi() - this.FuncList.get(0).getXi();
    	h2/=2.0;
    	FuncList.add(new FEMShapeFunction1D1Pow(this.left, h1, h2));
    	FuncList.add(new FEMShapeFunction1D1Pow(this.left + h2, h2, h2));
    		
    		
        for (int i = 1; i < this.FuncList.size()-1; i++) {
        	h1 = this.FuncList.get(i).getXi() - this.FuncList.get(i-1).getXi();
        	h1/=2.0;
        	h2 = this.FuncList.get(i+1).getXi() - this.FuncList.get(i).getXi();
        	h2/=2.0;
        	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(i).getXi(), h1, h2));
        	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(i).getXi() + h2, h2, h2));
        }
        
        h1 = this.FuncList.get(this.FuncList.size()-1).getXi() - this.FuncList.get(this.FuncList.size()-2).getXi();
    	h1/=2.0;
    	h2=0.001;
    	FuncList.add(new FEMShapeFunction1D1Pow(this.FuncList.get(this.FuncList.size()-1).getXi(), h1, h2));
        int n = FuncList.size();
		double res[] = null;
		
		MatrixGenerator1 gen = new MatrixGenerator1(left, right);
        gen.setLeft(left);
        gen.setRight(right);

            gen.setF1(FuncList.get(0));
            gen.setF2(FuncList.get(1));
            double tmpb = 0;
            double[] bNew = new double[A.getN()];
            
            gen.setF1(FuncList.get(0));
			tmpb = gen.getFe(f);
			bNew[0]+=tmpb;
            gen.setF1(FuncList.get(1));
            tmpb = gen.getFe(f);
            bNew[0]+=tmpb;
            int jpos = 1;
		for (int i = 1; i < bNew.length-1; i++) {
			gen.setF1(FuncList.get(jpos));
			tmpb = gen.getFe(f);
			bNew[i]+=tmpb;
			gen.setF1(FuncList.get(jpos+1));
			tmpb = gen.getFe(f);
			bNew[i]+=tmpb;
            gen.setF1(FuncList.get(jpos+2));
            tmpb = gen.getFe(f);
            bNew[i]+=tmpb;
            jpos+=2;
		}
		gen.setF1(FuncList.get(FuncList.size()-2));
		tmpb = gen.getFe(f);
		bNew[bNew.length-1]+=tmpb;
		gen.setF1(FuncList.get(FuncList.size()-1));
		tmpb = gen.getFe(f);
		bNew[bNew.length-1]+=tmpb;
		
        
        
        //        GaussQuadrature gau = new GaussQuadrature(10);
//        
//        
//        for (int i = 0; i < b.length; i++) {
//        	final FEMShapeFunction1D1Pow v = FuncList.get(i);
//        	IFunction1D fff = new IFunction1D() {
//				
//				@Override
//				public double calculateDerivaty(double x) {
//					// TODO Auto-generated method stub
//					return 0;
//				}
//				
//				@Override
//				public double calculate(double x) {
//					double uVal = femres.calculate(x);//f1.calculate(x)*u1+f2.calculate(x)*u2;
//					double uDerVal = femres.calculateDerivaty(x);//f1.calculateDerivaty(x)*u1+f2.calculateDerivaty(x)*u2;
//					return uDerVal*p.calculate(x)*v.calculateDerivaty(x) + uVal*w.calculate(x)*v.calculateDerivaty(x) + uVal*q.calculate(x)*v.calculate(x);
//				}
//			};
//			
//			double tmpxz = gau.justGauss(this.left, this.right, fff); 
////			System.out.println(tmpxz);
////			b[i] -= tmpxz;
//		}
        
		bNew[0] = 0.0;
        A.setValue(0, 1, 0.0);
        A.setValue(0, 0, 1.0);
        bNew[bNew.length-1] = 0.0;
		A.setValue(bNew.length-1, bNew.length-2, 0.0);
		A.setValue(bNew.length-1, bNew.length-1, 1.0);
        
        
//        double[] tmpU = new double[b.length];
		for (int j = 0; j < bNew.length; j++) {
//			ArrayList<Integer> pos = A.getJRowIndex(j);
//			double tmpxz = 0.0;
//			double tmpxz2 = 0.0;
//			for (int i = 0; i < pos.size(); i++) {
//				tmpxz += A.getValue(j, pos.get(i))*femres.res[pos.get(i)];//calculate(FuncList.get(pos.get(i)).getXi());
////				tmpxz2 += this.A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
//			}
//			bNew[j]-=tmpxz;
			bNew[j]-=b[j];
		}
        
//		b[0]+= (f1.calculateDerivaty((f1.getXi()-f1.gethLeft()/2.0)) + f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0)))*(u1)/2.0  - f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0))*u1;
//		b[n-1]+= (f2.calculateDerivaty((f2.getXi()-f2.gethLeft()/2.0)) + f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0)))*(u2)/2.0 - f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0))*u2;
        

        LUFactorization lu = new LUFactorization(A);
        res = lu.calculate(bNew);
//        for (int i = 0; i < res.length; i++) {
//			System.out.println(res[i]);
//		}
//        	XYSeriesCollection col = new XYSeriesCollection();
//        
//            		 	XYSeries series = new XYSeries("", true, true);
//            	        for (int i = 0; i < NodeList.size(); i++) {
//        					series.add((double)NodeList.get(i),res[i]);
//        				}
//            	        col.addSeries(series);
//        
//                NewOkCancelDialog dialog = new NewOkCancelDialog(null, false, col);
//                dialog.setLocationRelativeTo(null);
//                dialog.setVisible(true);
		
		return new FEMResult(res, this.FuncList);
	}
    
    public double[] errorInside(int i1,int i2, final double u1,final double u2) {
    	int n = 7;
		double res[] = null;
		HashMatrix2 A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, n);
		double[] b = new double[n];
		final FEMShapeFunction1D1Pow f1 = FuncList.get(i1);
        final FEMShapeFunction1D1Pow f2 = FuncList.get(i2);
		ArrayList<FEMShapeFunction1D1Pow> FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
		double h1 = (f2.getXi()-f1.getXi())/(double)(n-1);
        for (int i = 0; i < n; i++) {
            FuncList.add(new FEMShapeFunction1D1Pow(f1.getXi()+h1*i, h1,h1));
        }
        
        StatMatrixGenerator gen = new StatMatrixGenerator();
        gen.setLeft(f1.getXi());
        gen.setRight(f2.getXi());

            gen.setF1(FuncList.get(0));
            gen.setF2(FuncList.get(1));
            double[][] tmp = null;
            double[] tmpb = null;

        for (int i = 0; i < b.length-1; i++) {
            gen.setF1(FuncList.get(i));
            gen.setF2(FuncList.get(i+1));
            tmp = gen.getAll(p, q, w);
            tmpb = gen.getFe(f);

            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
            b[i]+=tmpb[0];
            b[i+1]+=tmpb[1];
        }

//		b[0]+= (f1.calculateDerivaty((f1.getXi()-f1.gethLeft()/2.0)) + f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0)))*(u1)/2.0  - f1.calculateDerivaty((f1.getXi()+f1.gethRight()/2.0))*u1;
//		b[n-1]+= (f2.calculateDerivaty((f2.getXi()-f2.gethLeft()/2.0)) + f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0)))*(u2)/2.0 - f2.calculateDerivaty((f2.getXi()+f2.gethRight()/2.0))*u2;
//		b[n-1] = 0.0;
//		A.setValue(n-1, n-2, 0.0);
		
        
		
		double[] tmpU = new double[b.length];
		for (int j = 0; j < tmpU.length; j++) {
			ArrayList<Integer> pos = A.getJRowIndex(j);
			double tmpxz = 0.0;
//			double tmpxz2 = 0.0;
			for (int i = 0; i < pos.size(); i++) {
				tmpxz += A.getValue(j, pos.get(i))*(u1*f1.calculate(FuncList.get(pos.get(i)).getXi()) + u2*f2.calculate(FuncList.get(pos.get(i)).getXi()) ) ;            //femres.calculate(FuncList.get(pos.get(i)).getXi());
//				tmpxz2 += this.A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
			}
			b[j]-=tmpxz;
		}
		
		A.setValue(0, 0, 1.0);
		A.setValue(1, 0, 0.0);
		A.setValue(0, 1, 0.0);
		b[0] = 0.0;
		
		A.setValue(6, 6, 1.0);
		A.setValue(6, 5, 0.0);
		A.setValue(5, 6, 0.0);
		b[6] = 0.0;
		
        LUFactorization lu = new LUFactorization(A);
        res = lu.calculate(b);
//        for (int i = 0; i < res.length; i++) {
//			System.out.println(res[i]);
//		}
		
		return res;
	}
    
    public double[] errorBoundaries(boolean isLeft, final double u1,final double u2) {
    	int n = 7;
		double res[] = null;
		HashMatrix2 A = new HashMatrix2(HashMatrix2.ARRAY_TYPE, n);
		double[] b = new double[n];
		
		if (isLeft) {
			final FEMShapeFunction1D1Pow f1 = FuncList.get(0);
	        final FEMShapeFunction1D1Pow f2 = FuncList.get(1);
	        
	        ArrayList<FEMShapeFunction1D1Pow> FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
			double h1 = (f2.getXi()-f1.getXi())/(double)(n-1);
	        for (int i = 0; i < n; i++) {
	            FuncList.add(new FEMShapeFunction1D1Pow(f1.getXi()+h1*i, h1,h1));
	        }
	        
	        StatMatrixGenerator gen = new StatMatrixGenerator();
	        gen.setLeft(f1.getXi());
	        gen.setRight(f2.getXi());

	            gen.setF1(FuncList.get(0));
	            gen.setF2(FuncList.get(1));
	            double[][] tmp = null;
	            double[] tmpb = null;

	        for (int i = 0; i < b.length-1; i++) {
	            gen.setF1(FuncList.get(i));
	            gen.setF2(FuncList.get(i+1));
	            tmp = gen.getAll(p, q, w);
	            tmpb = gen.getFe(f);

	            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
	            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
	            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
	            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
	            b[i]+=tmpb[0];
	            b[i+1]+=tmpb[1];
	        }
			A.setValue(0, 0, 1.0);
			A.setValue(0, 1, 0.0);
			A.setValue(0, 2, 0.0);
			b[0] = 0.0;
			
			
			double[] tmpU = new double[b.length];
			for (int j = 0; j < tmpU.length; j++) {
				ArrayList<Integer> pos = A.getJRowIndex(j);
				double tmpxz = 0.0;
//				double tmpxz2 = 0.0;
				for (int i = 0; i < pos.size(); i++) {
					tmpxz += A.getValue(j, pos.get(i))*(u1*f1.calculate(FuncList.get(pos.get(i)).getXi()) + u2*f2.calculate(FuncList.get(pos.get(i)).getXi()) ) ;            //femres.calculate(FuncList.get(pos.get(i)).getXi());
//					tmpxz2 += this.A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
				}
				b[j]-=tmpxz;
			}
			
	        LUFactorization lu = new LUFactorization(A);
	        res = lu.calculate(b);
//	        for (int i = 0; i < res.length; i++) {
//				System.out.println(res[i]);
//			}
	        
	        
		} else {
			final FEMShapeFunction1D1Pow f1 = FuncList.get(FuncList.size()-2);
	        final FEMShapeFunction1D1Pow f2 = FuncList.get(FuncList.size()-1);
	        
	        ArrayList<FEMShapeFunction1D1Pow> FuncList = new ArrayList<FEMShapeFunction1D1Pow>();
			double h1 = (f2.getXi()-f1.getXi())/(double)(n-1);
	        for (int i = 0; i < n; i++) {
	            FuncList.add(new FEMShapeFunction1D1Pow(f1.getXi()+h1*i, h1,h1));
	        }
	        
	        StatMatrixGenerator gen = new StatMatrixGenerator();
	        gen.setLeft(f1.getXi());
	        gen.setRight(f2.getXi());

	            gen.setF1(FuncList.get(0));
	            gen.setF2(FuncList.get(1));
	            double[][] tmp = null;
	            double[] tmpb = null;

	        for (int i = 0; i < b.length-1; i++) {
	            gen.setF1(FuncList.get(i));
	            gen.setF2(FuncList.get(i+1));
	            tmp = gen.getAll(p, q, w);
	            tmpb = gen.getFe(f);

	            A.setValue(i, i, A.getValue(i, i) + tmp[0][0]);
	            A.setValue(i, i+1, A.getValue(i, i+1) + tmp[0][1]);
	            A.setValue(i+1, i, A.getValue(i+1, i) + tmp[1][0]);
	            A.setValue(i+1, i+1, A.getValue(i+1, i+1) + tmp[1][1]);
	            b[i]+=tmpb[0];
	            b[i+1]+=tmpb[1];
	        }
			
			A.setValue(n-1, n-1, 1.0);
			A.setValue(n-1, n-2, 0.0);
			A.setValue(n-1, n-3, 0.0);
			b[n-1] = 0.0;
			
			double[] tmpU = new double[b.length];
			for (int j = 0; j < tmpU.length; j++) {
				ArrayList<Integer> pos = A.getJRowIndex(j);
				double tmpxz = 0.0;
//				double tmpxz2 = 0.0;
				for (int i = 0; i < pos.size(); i++) {
					tmpxz += A.getValue(j, pos.get(i))*(u1*f1.calculate(FuncList.get(pos.get(i)).getXi()) + u2*f2.calculate(FuncList.get(pos.get(i)).getXi()) ) ;            //femres.calculate(FuncList.get(pos.get(i)).getXi());
//					tmpxz2 += this.A.getValue(j, pos.get(i))*femres.calculate(FuncList.get(pos.get(i)).getXi());
				}
				b[j]-=tmpxz;
			}
			
	        LUFactorization lu = new LUFactorization(A);
	        res = lu.calculate(b);
//	        for (int i = 0; i < res.length; i++) {
//				System.out.println(res[i]);
//			}
		}
		
		
		
		return res;
	}

    public static void main(String[] args){
        ArrayList<Double> list = new ArrayList<Double>();
        double a = 0.0;
        double b = 1.0;
        int N = 10;
        double h = (b-a)/N;
        for (int i = 0; i <= N; i++) {
            list.add(a+h*i);
        }
//        
//        a=0.5;
//        b =1;
//        N = 20;
//        h = (b-a)/N;
////        a+=h;
//        for (int i = 1; i <= N; i++) {
//            list.add(a+h*i);
//        }


        AdaptiveScheme gen = new AdaptiveScheme(list);

            gen.setLeft(a);
            gen.setRight(b);
            gen.setfString("100");
            gen.setwString("100");
            gen.setqString("0");
            gen.setpString("1");
            gen.setDirihetB(true);
            gen.setBVal(0.0);
            gen.setDirihetA(true);
            gen.setAVal(0.0);

        gen.adaptate(0.002);
//        gen.Solve("");
    }

}
